package distributed

import (
	"context"
	"fmt"
	"github.com/robfig/cron/v3"
	"log"
	"sync"
	"time"

	"go-caipu/pkg/services/schedule"
	"go-caipu/pkg/services/schedule/models"
)

type JobExec interface {
	Exec(arg interface{}) error
}

func CallExec(e JobExec, arg interface{}) error {
	return e.Exec(arg)
}

type TaskScheduler struct {
	cron        *cron.Cron
	db          schedule.Service
	Coordinator *Coordinator
	tasks       map[int]cron.EntryID
	mu          sync.RWMutex
	JobList     map[string]JobExec
}

// NewTaskScheduler 创建一个新的任务调度器
func NewTaskScheduler(db schedule.Service, coordinator *Coordinator) *TaskScheduler {
	return &TaskScheduler{
		cron:        cron.New(cron.WithSeconds()),
		db:          db,
		Coordinator: coordinator,
		tasks:       make(map[int]cron.EntryID),
	}
}

func (ts *TaskScheduler) Start() {
	cmd := schedule.GetSysJobPageCommand{}
	cmd.PageSize = 1000
	cmd.Status = 1
	tasks, _, err := ts.db.GetSysJobPage(context.Background(), cmd)
	if err != nil || len(tasks) == 0 {
		log.Printf("Failed to load tasks: %v", err)
		return
	}
	for _, task := range tasks {
		ts.AddTask(task)
	}
	ts.cron.Start()
}
func (ts *TaskScheduler) Stop() {
	ts.cron.Stop()
}

// AddTask 添加一个新任务
func (ts *TaskScheduler) AddTask(task schedule.SysJob) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	//已在队列中
	if _, exists := ts.tasks[task.JobId]; exists {
		return
	}
	entryID, err := ts.cron.AddFunc(task.CronExpression, ts.createJobFunc(task))
	if err != nil {
		log.Printf("Failed to add task %d: %v", task.JobId, err)
		return
	}
	ts.tasks[task.JobId] = entryID
	log.Printf("Task %d scheduled with spec %s", task.JobId, task.CronExpression)
}
func (ts *TaskScheduler) RemoveTask(taskID int) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	if entryID, exists := ts.tasks[taskID]; exists {
		ts.cron.Remove(entryID)
		delete(ts.tasks, taskID)
		log.Printf("Removed task %d from scheduler", taskID)
	}
}
func (ts *TaskScheduler) createJobFunc(task schedule.SysJob) func() {
	return func() {
		//尝试获取分布式锁
		locked, err := ts.Coordinator.TryLockTask(task.JobId)
		if err != nil {
			log.Printf("Failed to lock task %d: %v", task.JobId, err)
			return
		}
		if !locked {
			return
		}
		defer func() {
			if err := ts.Coordinator.UnlockTask(task.JobId); err != nil {
				log.Printf("Failed to release lock for task %d: %v", task.JobId, err)
			}
		}()

		//1.记录任务开始时间
		execution := models.SysJobLog{
			JobID:     task.JobId,
			JobName:   task.JobName,
			JobGroup:  task.JobGroup,
			Args:      task.Args,
			Status:    2,
			NodeID:    ts.Coordinator.nodeID,
			StartTime: time.Now(),
		}
		ts.db.InsertJobLog(context.Background(), &execution)
		//2.执行任务
		var obj = ts.JobList[task.InvokeTarget]
		if obj == nil {
			fmt.Println("[Job] ExecJob Run job nil")
			return
		}
		err = CallExec(obj.(JobExec), task.Args)
		if err != nil {
			// 如果失败暂停一段时间重试
			fmt.Println(time.Now().Format("2006-01-02 15:04:05"), " [ERROR] mission failed! ", err)
			execution.Status = 3
			execution.ErrorMsg = err.Error()
		} else {
			execution.Status = 1
		}

		//3. 记录任务结束时间
		execution.EndTime = time.Now()
		execution.Duration = execution.EndTime.Sub(execution.StartTime).Milliseconds()
		ts.db.UpdateJobLog(context.Background(), &execution)
		//更新任务状态

	}
}
func executeTask(command string) (string, error) {
	// 实现具体的任务执行逻辑
	// 可以是HTTP请求、shell命令执行等
	log.Print("task success")
	return "Task executed successfully", nil
}
